﻿using CarbonExchange.Bll;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using CarbonExchange.AmeeQuery;
using System.Linq;
using System;
using System.Collections.Generic;

namespace CarbonExchange.Tests
{
    [TestClass()]
    public class SectionTest : BaseTest
    {

        [TestMethod]
        public void Section_GetById_ReturnsNull_WithIncorrectId()
        {
            SectionFactory factory = new SectionFactory(_Context);
            Assert.IsNull(factory.GetById(int.MaxValue));
        }

        [TestMethod]
        public void Section_GetById_ReturnsNotNull_WithCorrectId()
        {
            SectionFactory factory = new SectionFactory(_Context);
            Assert.IsNotNull(factory.GetById(_TestSections[0].Id));
        }

        [TestMethod]
        public void Section_GetById_ReturnsCorrectProperties()
        {
            SectionFactory factory = new SectionFactory(_Context);
            Section section = factory.GetById(_TestSections[1].Id);
            Assert.IsNotNull(section);
            Assert.AreEqual(_TestSections[1].Id, section.Id);
            Assert.AreEqual("Water", section.Name);
            Assert.AreEqual(DateTime.Parse("24/10/1975 12:00:00"), section.Created);
        }

        [TestMethod]
        public void Section_GetAll_ReturnsList_WithCorrectCount()
        {
            SectionFactory factory = new SectionFactory(_Context);
            Assert.AreEqual(_TestSections.Count, factory.GetAll().Count());
        }

        [TestMethod]
        public void Section_GetAll_ReturnsCorrectProperties()
        {
            SectionFactory factory = new SectionFactory(_Context);
            List<Section> sections = factory.GetAll().ToList();
            Assert.IsNotNull(sections);
            Assert.AreEqual(_TestSections.Count, sections.Count);
            foreach (Section section in sections)
            {
                Assert.AreEqual(_TestSections[sections.IndexOf(section)].Id, section.Id);
                Assert.AreEqual(_TestSections[sections.IndexOf(section)].Name, section.Name);
                Assert.AreEqual(_TestSections[sections.IndexOf(section)].Created.ToLocalTime(), section.Created);
                Assert.AreEqual(_TestSections[sections.IndexOf(section)].Sequence, section.Sequence);
            }
        }


        [TestMethod]
        public void Section_InsertOne()
        {
            SectionFactory factory = new SectionFactory(_Context);
            Section section = new Section();
            section.Name = "Shopping";

            DateTime expectedDateTime = DateTime.Now;
            factory.Save(section);

            Assert.IsTrue(section.Id > 0);
            Assert.AreEqual("Shopping", section.Name);
            Assert.AreEqual(expectedDateTime.ToLongDateString(), section.Created.ToLongDateString());
            Assert.AreEqual(expectedDateTime.ToLongTimeString(), section.Created.ToLongTimeString());

            int id = section.Id;

            Section section2 = factory.GetById(id);
            Assert.IsNotNull(section2);
            Assert.AreEqual(section.Id, section2.Id);
            Assert.AreEqual(section.Name, section2.Name);
            Assert.AreEqual(section.Created, section2.Created);
        }

        [TestMethod]
        public void Section_InsertMany()
        {
            SectionFactory factory = new SectionFactory(_Context);

            int existingCount = factory.GetAll().Count();
            int loopCount = 5;
            List<Section> updates = new List<Section>();
            for (int i = 0; i < loopCount; i++)
            {
                Section section = new Section();
                section.Name = string.Format("Insert Test {0}", i);
                updates.Add(section);
            }

            DateTime expectedDateTime = DateTime.Now;
            factory.Save(updates.AsQueryable());
            int[] tmpIds = new int[loopCount];

            for (int i = 0; i < loopCount; i++)
            {
                tmpIds[i] = updates[i].Id;
                Assert.IsTrue(updates[i].Id > 0);
                Assert.AreEqual(string.Format("Insert Test {0}", i), updates[i].Name);
                Assert.IsTrue(TimeSpan.FromMinutes(1) > updates[i].Created - expectedDateTime);
            }

            var saved = factory.GetAll().Skip(existingCount).ToArray();
            Assert.AreEqual(loopCount, saved.Count());
            for (int i = 0; i < saved.Count(); i++)
            {
                Assert.AreEqual(tmpIds[i], saved[i].Id);
                Assert.AreEqual(string.Format("Insert Test {0}", i), saved[i].Name);
                Assert.IsTrue(saved[i].Created - expectedDateTime < TimeSpan.FromSeconds(1));
            }
        }

        [TestMethod]
        public void Section_UpdateOne()
        {
            SectionFactory factory = new SectionFactory(_Context);
            var tmp = factory.GetById(_TestSections[1].Id);
            tmp.Name = "Update Test";
            factory.Save(tmp);
            Assert.AreEqual("Update Test", tmp.Name);
            tmp = factory.GetById(_TestSections[1].Id);
            Assert.AreEqual("Update Test", tmp.Name);
        }

        [TestMethod]
        public void Section_UpdateMany()
        {
            SectionFactory factory = new SectionFactory(_Context);
            var tmp = factory.GetAll().ToArray();
            for (int i = 0; i < tmp.Count(); i++)
            {
                tmp.ElementAt(i).Name = string.Format("Update Test {0}", i);
            }
            factory.Save(tmp.AsQueryable());
            for (int i = 0; i < tmp.Count(); i++)
            {
                Assert.AreEqual(string.Format("Update Test {0}", i), tmp.ElementAt(i).Name);
            }
            tmp = factory.GetAll().ToArray();
            for (int i = 0; i < tmp.Count(); i++)
            {
                Assert.AreEqual(string.Format("Update Test {0}", i), tmp.ElementAt(i).Name);
            }
        }

        [TestMethod]
        public void Section_DeleteOne()
        {
            SectionFactory factory = new SectionFactory(_Context);
            Section section = factory.GetById(_TestSections[1].Id);
            Assert.IsNotNull(section);
            factory.Delete(section);
            Assert.AreEqual(_TestSections.Count -1, factory.GetAll().Count());
            section = factory.GetById(_TestSections[1].Id);
            Assert.IsNull(section);
        }

        [TestMethod]
        public void Section_DeleteMany()
        {
            SectionFactory factory = new SectionFactory(_Context);
            var sections = factory.GetAll();
            Assert.IsTrue(sections.Count() > 1);
            factory.Delete(sections);
            sections = factory.GetAll();
            Assert.AreEqual(0, sections.Count());
        }

        [TestMethod]
        public void Section_Move()
        {
            SectionFactory factory = new SectionFactory(_Context);

            var tmp = factory.GetAll().ToList();
            Assert.AreEqual(3, tmp.Count());

            tmp.ElementAt(0).Name = "Item Originally At 0";
            tmp.ElementAt(1).Name = "Item Originally At 1";
            tmp.ElementAt(2).Name = "Item Originally At 2";

            factory.Save(tmp);
            
            factory.Move(tmp, 2, 0);

            Assert.AreEqual("Item Originally At 2", tmp.ToArray()[0].Name);
            Assert.AreEqual("Item Originally At 0", tmp.ToArray()[1].Name);
            Assert.AreEqual("Item Originally At 1", tmp.ToArray()[2].Name);

            tmp = factory.GetAll().ToList();

            Assert.AreEqual("Item Originally At 2", tmp.ToArray()[0].Name);
            Assert.AreEqual("Item Originally At 0", tmp.ToArray()[1].Name);
            Assert.AreEqual("Item Originally At 1", tmp.ToArray()[2].Name);

            factory.Move(tmp, 1, 2);

            Assert.AreEqual("Item Originally At 2", tmp.ToArray()[0].Name);
            Assert.AreEqual("Item Originally At 1", tmp.ToArray()[1].Name);
            Assert.AreEqual("Item Originally At 0", tmp.ToArray()[2].Name);

            tmp = factory.GetAll().ToList();

            Assert.AreEqual("Item Originally At 2", tmp.ToArray()[0].Name);
            Assert.AreEqual("Item Originally At 1", tmp.ToArray()[1].Name);
            Assert.AreEqual("Item Originally At 0", tmp.ToArray()[2].Name);
        }

        [TestMethod]
        public void Section_Swap()
        {
            SectionFactory factory = new SectionFactory(_Context);

            IList<Section> tmp = factory.GetAll().ToList();
            Assert.AreEqual(3, tmp.Count());

            tmp[0].Name = "Item Originally At 0";
            tmp[1].Name = "Item Originally At 1";
            tmp[2].Name = "Item Originally At 2";

            factory.Save(tmp);
            
            factory.Swap(tmp, 2, 0);

            Assert.AreEqual("Item Originally At 2", tmp.ToArray()[0].Name);
            Assert.AreEqual("Item Originally At 1", tmp.ToArray()[1].Name);
            Assert.AreEqual("Item Originally At 0", tmp.ToArray()[2].Name);

            tmp = factory.GetAll().ToList();

            Assert.AreEqual("Item Originally At 2", tmp.ToArray()[0].Name);
            Assert.AreEqual("Item Originally At 1", tmp.ToArray()[1].Name);
            Assert.AreEqual("Item Originally At 0", tmp.ToArray()[2].Name);

            factory.Move(tmp, 1, 2);

            Assert.AreEqual("Item Originally At 2", tmp.ToArray()[0].Name);
            Assert.AreEqual("Item Originally At 0", tmp.ToArray()[1].Name);
            Assert.AreEqual("Item Originally At 1", tmp.ToArray()[2].Name);

            tmp = factory.GetAll().ToList();

            Assert.AreEqual("Item Originally At 2", tmp.ToArray()[0].Name);
            Assert.AreEqual("Item Originally At 0", tmp.ToArray()[1].Name);
            Assert.AreEqual("Item Originally At 1", tmp.ToArray()[2].Name);
        }

        [TestMethod]
        public void Section_InsertFirst()
        {
            SectionFactory factory = new SectionFactory(_Context);
            factory.Delete(factory.GetAll());
            Section tmp = new Section();
            tmp.Name = "InsertFirstTest";
            factory.Save(tmp);
            Assert.AreEqual("InsertFirstTest", tmp.Name);
            Assert.IsTrue(tmp.Id > 0);
            Assert.AreEqual(0, tmp.Sequence);

            Section tmp2 = factory.GetById(tmp.Id);
            Assert.AreEqual(tmp.Id, tmp2.Id);
            Assert.AreEqual(tmp.Name, tmp2.Name);
            Assert.AreEqual(tmp.Created, tmp2.Created);
            Assert.AreEqual(0, tmp2.Sequence);
        }
    }
}
